
#include "stdinc.h"
#include <stdlib.h>
#include "clock.h"

//#define USE_HSE_AS_SYSCLK
#define USE_HSI_AS_SYSCLK

//#define USE_LSE_AS_RTCCLK
#define USE_LSI_AS_RTCCLK


#ifdef USE_HSI_AS_SYSCLK

/// 一次 OS 时钟中断的间隔
#define OS_CLOCK_INTERVER_US (65000L)
#define OS_CLOCK_INTERVER_MS (OS_CLOCK_INTERVER_US/1000L)

/// 看门狗最小喂狗时间ms
#define WATCHDOG_FEED_MAX_TIME  1500

/// @brief 系统主时钟初始化(HSI)
void SysClock_init(void) {
	uint16_t seed;
	// 启用 HSI (内部高速时钟)
	CLK_HSICmd(ENABLE);
	// 等待 HSI 时钟稳定
	while (CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == RESET) { seed++; }
	// 设置系统时钟为 HSI
	CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);
	// 设置时钟分频数为 1 (16 MHz)
	CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
	// 等待系统时钟稳定输出 16MHz
	while(CLK_GetClockFreq() != HSI_VALUE) { seed++; }
	// 随机数序列初始化
	srand(seed);
}

#else

/// @brief 系统主时钟初始化(HSE)
void SysClock_init(void) {
	// 外部时钟开
	CLK_HSEConfig(CLK_HSE_ON);
	// 内部低频RC开
	CLK_LSICmd(ENABLE);
	// 内部高频RC开
	CLK_HSICmd(ENABLE);

	// 等待 HSE 时钟稳定
	while (CLK_GetFlagStatus(CLK_FLAG_HSERDY) == RESET);
	// 设置系统时钟为 HSE
	CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSE);
	// 设置时钟分频数为 1 (16 MHz)
	CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
	// 等待系统时钟稳定输出 16MHz
	while (CLK_GetClockFreq() != HSE_VALUE);

	// 开启时钟安全系统
	CLK_ClockSecuritySystemEnable();
}

#endif


/// @brief us 计数器
uint32_t _tick_count_us = 0;
/// @brief ms 计数器
uint32_t _tick_count_ms = 0;
/// @brief s 计数器
uint32_t _tick_count_s = 0;

//
// 操作系统时钟配置
//
void osClockInit() {
	// TIM2(16位) 用于系统时钟滴答计数
	CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
	// TIM3(16位) 用于 us 级精准定时任务
	CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, ENABLE);

	// 配置为 1us 计数一次 / 65ms(65000us) 中断一次
	// TIM2_Prescaler_16: 16M主时钟/16 = 1us 计数一次
	// 65000*1us (即65ms)定时中断一次
	TIM2_DeInit();
	TIM2_TimeBaseInit(TIM2_Prescaler_16, TIM2_CounterMode_Up, OS_CLOCK_INTERVER_US-1);
	TIM2_PrescalerConfig(TIM2_Prescaler_16, TIM2_PSCReloadMode_Immediate);
	TIM2_ARRPreloadConfig(ENABLE);

	// 使能中断
	TIM2_ITConfig(TIM2_IT_Update, ENABLE);

	// 开始计时
	TIM2_SetCounter(0x0000);
	_tick_count_us = 0;
	TIM2_Cmd(ENABLE);
}

#define GET_US_COUNTER() 			(*((uint16_t*)&(TIM2->CNTRH)))
#define US_COUNTER_OVERFLOW() 		(TIM2->SR1 & 0x01)
#define US_COUNTER_OVERFLOW_CLEAR() (TIM2->SR1 &= (~0x01))

// !!! 32 位加减乘除运算耗时:6~7us !!!
void osClockTickIrqHandler() {
	_tick_count_us += OS_CLOCK_INTERVER_US;
	_tick_count_ms += OS_CLOCK_INTERVER_MS;
	// 如果毫秒数千位有进位，则秒数加1
	if((_tick_count_ms%1000) < OS_CLOCK_INTERVER_MS) { _tick_count_s++; }
}

uint32_t osGetUs() {
	// _tick_count_us 中的计数值加上当前us计数器的值，就是当前的us数
	return (_tick_count_us + GET_US_COUNTER());
}

uint32_t osElapsedUs(uint32_t last) {
	uint32_t now = osGetUs();

	if(now >= last) {
		return now - last;
	} else {
		return (0xFFFFFFFFL - last) + now;
	}
}

uint32_t osElapsedMs(uint32_t last) {
	uint32_t now = osGetMs();

	if(now >= last) {
		return now - last;
	} else {
		return (0xFFFFFFFFL - last) + now + 1;
	}
}

void osDelayUs(uint16_t nus) {
	uint8_t overflow;
	uint16_t start, now;

	start = now = GET_US_COUNTER();
	overflow = 0;

	if( US_COUNTER_OVERFLOW() ) {
		osClockTickIrqHandler();
		US_COUNTER_OVERFLOW_CLEAR();
	}

	while(1) {
		if( !overflow ) {
			if((now - start) >= nus) { return; }
		} else {
			if(((OS_CLOCK_INTERVER_US - start + now) >= nus) || (now >= start)) { return; }
		}

		Watchdog_feed();

		if( US_COUNTER_OVERFLOW() ) {
			osClockTickIrqHandler();
			US_COUNTER_OVERFLOW_CLEAR();
			overflow = 1;
		}
		now = GET_US_COUNTER();
	}
}

void osDelayMs(uint32_t nms) {
	uint32_t now = osGetMs();
	while(osElapsedMs(now) < nms) { Watchdog_feed(); }
}

void osHPTimerSet(uint16_t interval) {
	if(interval < 2) { return; }
	interval -= 2;	// 修正此函数本身的时间开销
	TIM3->ARRH = (uint8_t)(interval >> 8);
	TIM3->ARRL = (uint8_t)(interval);
	TIM3->CR1 |= TIM_CR1_CEN;				// 时钟使能
	TIM3->IER |= (uint8_t)TIM3_IT_Update;	// 中断使能
	TIM3->CNTRH = 0;
	TIM3->CNTRL = 0;
}


// stm8 rtc时钟可以使用内部低频时钟源，或者外部低速32768Hz时钟源
void RTC_init() {
	RTC_InitTypeDef RTC_InitStruct;

	RTC_DeInit();
	CLK_PeripheralClockConfig(CLK_Peripheral_RTC, ENABLE);

#ifdef USE_LSI_AS_RTCCLK
	// 使用 LSI 做为时钟源(据说很不准！)
	CLK_LSICmd(ENABLE);
	while(CLK_GetFlagStatus(CLK_FLAG_LSIRDY) == RESET);
	// LSI = 38KHz, CLK_RTCCLKDiv_1 = 38KHz
	CLK_RTCClockConfig(CLK_RTCCLKSource_LSI, CLK_RTCCLKDiv_1);

	// 设置时间格式
	RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
	// 设置 APREDiv/SPREDiv 为日历时钟提供 1s 的时钟输入
	RTC_InitStruct.RTC_AsynchPrediv = 124;
	RTC_InitStruct.RTC_SynchPrediv = 303;
	RTC_Init(&RTC_InitStruct);
#else
	// 使用 LSE 做为时钟源
	CLK_LSEConfig(CLK_LSE_ON);
	while(CLK_GetFlagStatus(CLK_FLAG_LSERDY) == RESET);
	CLK_RTCClockConfig(CLK_RTCCLKSource_LSE, CLK_RTCCLKDiv_1);

	// 设置时间格式
	RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
	// 设置 APREDiv/SPREDiv 为日历时钟提供 1s 的时钟输入
	RTC_InitStruct.RTC_AsynchPrediv = 127;
	RTC_InitStruct.RTC_SynchPrediv = 255;
	RTC_Init(&RTC_InitStruct);
#endif
}

/// 设置 RTC 唤醒时间间隔
void RTC_setWakeupInterval(uint16_t count) {
	RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16); //19k/16=1.1875KHz t=0.85ms
	RTC_ITConfig(RTC_IT_WUT, ENABLE); 					 //开启中断
	RTC_SetWakeUpCounter(count); 						 //设置RTC Weakup计算器初值
	RTC_WakeUpCmd(ENABLE); 								 //使能自动唤醒
}

void RTC_irqHandler() {
	RTC_WakeUpCmd(DISABLE);
}

void RTC_setDateTime(DateTime dt) {
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_DateTypeDef RTC_DateStruct;

	RTC_DateStructInit(&RTC_DateStruct);
	RTC_DateStruct.RTC_WeekDay = (RTC_Weekday_TypeDef)dt.date.weekday;
	RTC_DateStruct.RTC_Date = dt.date.day;
	RTC_DateStruct.RTC_Month = (RTC_Month_TypeDef)dt.date.month;
	RTC_DateStruct.RTC_Year = dt.date.year%100;
	RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);

	RTC_TimeStructInit(&RTC_TimeStruct);
	RTC_TimeStruct.RTC_Hours = dt.time.hour;
	RTC_TimeStruct.RTC_Minutes = dt.time.minute;
	RTC_TimeStruct.RTC_Seconds = dt.time.second;
	RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
}

DateTime RTC_getDateTime() {
	RTC_DateTypeDef date;
	RTC_TimeTypeDef time;
	DateTime dt;

	// !!! 注意：每次Get之前，都必须先同步，即使刚同步过，也必须重新同步 !!!
	while(RTC_WaitForSynchro() != SUCCESS);
	RTC_GetDate(RTC_Format_BIN, &date);
	// !!! 注意：每次Get之前，都必须先同步，即使刚同步过，也必须重新同步 !!!
	while(RTC_WaitForSynchro() != SUCCESS);
	RTC_GetTime(RTC_Format_BIN, &time);

	dt.date.year = date.RTC_Year;
	dt.date.month = date.RTC_Month;
	dt.date.day = date.RTC_Date;
	dt.date.weekday = date.RTC_WeekDay;

	dt.time.hour = time.RTC_Hours;
	dt.time.minute = time.RTC_Minutes;
	dt.time.second = time.RTC_Seconds;

	return dt;
}

uint32_t RTC_getClock() {
	RTC_TimeTypeDef time;

	// !!! 注意：每次Get之前，都必须先同步，即使刚同步过，也必须重新同步 !!!
	while(RTC_WaitForSynchro() != SUCCESS);
	RTC_GetTime(RTC_Format_BIN, &time);

	return time.RTC_Hours*3600 + time.RTC_Minutes*60 + time.RTC_Seconds;
}

bool RTC_isInitTime() {
	RTC_TimeTypeDef time;
	while(RTC_WaitForSynchro() != SUCCESS);
	RTC_GetTime(RTC_Format_BIN, &time);
	return (!time.RTC_Hours && !time.RTC_Minutes && !time.RTC_Seconds);
}
